package org.ysling.litemall.core.service;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.ysling.litemall.core.system.SystemConfig;
import org.ysling.litemall.core.utils.GlobalWebUtil;
import org.ysling.litemall.core.utils.response.ResponseUtil;
import org.ysling.litemall.core.utils.ip.IpUtil;
import org.ysling.litemall.db.service.*;
import org.ysling.litemall.db.domain.*;
import org.ysling.litemall.db.enums.DealType;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * 用户余额交易记录
 * @author Ysling
 */
@Slf4j
@Service
public class DealingSlipCoreService {
    
    @Autowired
    private IUserService userService;
    @Autowired
    private IDealingSlipService dealingSlipService;
    @Autowired
    private ActionLogService logService;
    @Autowired
    private CommonService commonService;


    /**
     * 判断用户积分是否可以交易
     * @param userDeal 用户信息
     * @return null --> true
     */
    public Object isDeduction(LitemallUser userDeal){
        LitemallUser user = userService.findById(userDeal.getId());
        if (user == null){
            return ResponseUtil.fail("用户不存在");
        }

        if (user.getIntegral().compareTo(BigDecimal.ZERO) <= 0){
            return ResponseUtil.fail("余额不足");
        }

        //最近十次交易记录
        List<LitemallDealingSlip> dealingSlipList = commonService.querySelective(user.getId(), user.getOpenid());
        if (dealingSlipList.size() <= 0){
            return ResponseUtil.fail("资金异常");
        }

        BigDecimal lastBalance = dealingSlipList.get(0).getBalance();
        if (user.getIntegral().compareTo(lastBalance) != 0){
            return ResponseUtil.fail("资金异常");
        }

        //判断最近十次交易记录是否正常
        for (LitemallDealingSlip dealingSlip :dealingSlipList) {
            BigDecimal balance = dealingSlip.getBalance();
            if (lastBalance.compareTo(balance) != 0){
                return ResponseUtil.fail("资金异常");
            }
            BigDecimal award = dealingSlip.getAward();
            lastBalance = lastBalance.subtract(award);

            Short dealType = dealingSlip.getDealType();
            Short orderType = DealType.TYPE_ORDER.getType();
            Short cancelType = DealType.TYPE_ORDER_CANCEL.getType();
            if (dealType.equals(orderType) || dealType.equals(cancelType)){
                if (!commonService.countByOrderSn(dealingSlip.getOrderSn())){
                    return ResponseUtil.fail("资金异常");
                }
            }
        }
        return null;
    }




    /**
     * 添加系统修改金额交易记录
     * @param user 用户
     */
    public void systemIntegralUpdate(LitemallUser user){
        LitemallUser dealUser = userService.findById(user.getId());
        BigDecimal integral = user.getIntegral();
        BigDecimal dealIntegral = dealUser.getIntegral();

        if (integral.compareTo(dealIntegral) == 0){
            return;
        }

        HttpServletRequest request = GlobalWebUtil.getRequest();
        LitemallDealingSlip dealingSlip = new LitemallDealingSlip();
        dealingSlip.setUserId(dealUser.getId());
        dealingSlip.setOpenid(dealUser.getOpenid());
        dealingSlip.setBalance(integral);
        dealingSlip.setAward(integral.subtract(dealIntegral));
        dealingSlip.setRemark(DealType.TYPE_SYSTEM.getDepict());
        dealingSlip.setDealType(DealType.TYPE_SYSTEM.getType());
        dealingSlip.setLastDealIp(IpUtil.getIpAddr(request));
        dealingSlip.setTenantId(user.getTenantId());
        if (dealingSlipService.add(dealingSlip) == 0){
            throw new RuntimeException("交易记录添加失败,请重试");
        }

        logService.logGeneralSucceed("手动修改用户积分",String.format("积分：%s-->%s",dealIntegral,integral));
    }


    /**
     * 订单修改余额交易记录
     * @param order 订单
     * @param brand 店铺
     */
    public void addOrderIntegral(LitemallOrder order ,LitemallBrand brand){
        LitemallUser brandUser = isAddOrderIntegral(order , brand);
        if (brandUser == null){
            return;
        }
        // 获取订单商品信息
        LitemallOrderGoods orderGoods = commonService.findByGoodsOrderId(order.getId());
        if (orderGoods == null){
            return;
        }
        //优惠券金额
        BigDecimal couponPrice = order.getCouponPrice();
        //积分金额
        BigDecimal integralPrice = order.getIntegralPrice();
        //付款金额
        BigDecimal actualPrice = order.getActualPrice();
        //订单金额
        BigDecimal orderPrice = actualPrice.add(couponPrice).add(integralPrice);

        //添加赏金余额
        LitemallReward reward = commonService.findByRewardOrderId(order.getId());
        if (reward != null){
            LitemallUser creatorUser = userService.findById(reward.getCreatorUserId());
            // 赏金奖励 * 商品数量
            BigDecimal award = reward.getAward().multiply(BigDecimal.valueOf(orderGoods.getNumber()));
            // 添加积分
            addIntegral(creatorUser, order, award, DealType.TYPE_REWARD);
            // 从订单金额中扣除赏金金额
            orderPrice = orderPrice.subtract(award);
        }

        //添加分享余额
        LitemallShare share = commonService.findByShareOrderId(order.getId());
        if (share != null){
            LitemallUser inviterUser = userService.findById(share.getInviterId());
            // 添加积分
            addIntegral(inviterUser, order, share.getAward(), DealType.TYPE_SHARE);
        }

        LitemallUser user = userService.findById(brandUser.getId());
        //获取系统服务费比例 1%
        BigDecimal orderBrokerage = SystemConfig.getOrderBrokerage();
        //将比例转为小数 0.01
        orderBrokerage = orderBrokerage.divide(BigDecimal.valueOf(100) , 2 , RoundingMode.HALF_UP);
        //订单金额 - （服务费比例 * 订单金额）
        orderPrice = orderPrice.subtract(orderBrokerage.multiply(orderPrice));
        //添加订单余额
        addIntegral(user, order, orderPrice , DealType.TYPE_ORDER);
    }

    /**
     * 添加积分
     * @param user 用户信息
     * @param order 订单信息
     * @param award 添加金额
     * @param dealType 交易类型
     */
    public void addIntegral(LitemallUser user , LitemallOrder order , BigDecimal award , DealType dealType){
        BigDecimal integral = user.getIntegral();
        HttpServletRequest request = GlobalWebUtil.getRequest();
        LitemallDealingSlip dealingSlip = new LitemallDealingSlip();
        dealingSlip.setUserId(user.getId());
        dealingSlip.setOpenid(user.getOpenid());
        dealingSlip.setOrderSn(order.getOrderSn());
        dealingSlip.setAward(award);
        dealingSlip.setBalance(integral.add(award));
        dealingSlip.setRemark(dealType.getDepict());
        dealingSlip.setDealType(dealType.getType());
        dealingSlip.setLastDealIp(IpUtil.getIpAddr(request));
        if (dealingSlipService.add(dealingSlip) == 0){
            throw new RuntimeException("交易记录添加失败,请重试");
        }

        //增加用户积分
        user.setIntegral(integral.add(award));
        if (userService.updateVersionSelective(user) <= 0){
            throw new RuntimeException("增加用户积分失败,请重试");
        }
    }

    /**
     * 减少积分
     * @param user 用户信息
     * @param award 减少金额
     * @param dealType 交易类型
     */
    public void subtractIntegral(LitemallUser user ,LitemallOrder order, BigDecimal award , DealType dealType){
        BigDecimal integral = user.getIntegral();
        HttpServletRequest request = GlobalWebUtil.getRequest();
        LitemallDealingSlip dealingSlip = new LitemallDealingSlip();
        dealingSlip.setUserId(user.getId());
        dealingSlip.setOpenid(user.getOpenid());
        dealingSlip.setOrderSn(order.getOrderSn());
        //金额取反
        dealingSlip.setAward(award.negate());
        dealingSlip.setBalance(integral.subtract(award));
        dealingSlip.setRemark(dealType.getDepict());
        dealingSlip.setDealType(dealType.getType());
        dealingSlip.setLastDealIp(IpUtil.getIpAddr(request));
        if (dealingSlipService.add(dealingSlip) == 0){
            throw new RuntimeException("交易记录添加失败,请重试");
        }

        //减少用户积分
        user.setIntegral(integral.subtract(award));
        if (userService.updateVersionSelective(user) <= 0){
            throw new RuntimeException("减少用户积分失败,请重试");
        }
    }

    /**
     * 余额提现，减少积分并添加交易记录
     * @param user 用户信息
     * @param award 减少金额
     * @param dealingSlip 交易类型
     */
    public void subtractIntegral(LitemallUser user , BigDecimal award , LitemallDealingSlip dealingSlip){
        BigDecimal integral = user.getIntegral();
        HttpServletRequest request = GlobalWebUtil.getRequest();
        dealingSlip.setUserId(user.getId());
        dealingSlip.setOpenid(user.getOpenid());
        dealingSlip.setAward(award.negate());
        dealingSlip.setBalance(integral.subtract(award));
        dealingSlip.setLastDealIp(IpUtil.getIpAddr(request));

        // 这里添加失败不抛异常是因为余额已经提现，事务回滚没有意义，
        // 且可更具订单交易记录校验检验出错误记录
        dealingSlipService.add(dealingSlip);
        //减少用户积分
        user.setIntegral(integral.subtract(award));
        if (userService.updateVersionSelective(user) <= 0){
            throw new RuntimeException("减少用户积分失败,请重试");
        }
    }


    /**
     * 判断是否可以执行打款操作
     * @param brand 店铺信息
     * @param order 订单信息
     * @return      店铺用户
     */
    private LitemallUser isAddOrderIntegral(LitemallOrder order , LitemallBrand brand){
        //获取店铺所有者向店家打款
        if (brand == null || brand.getUserId() == null || brand.getUserId().equals("0")) {
            log.info("{发放交易余额}{未找到店铺--订单id:" + order.getId() +"}");
            logService.logOrderFail("发放交易余额","未找到店铺--订单id:" + order.getId());
            return null;
        }

        //判断订单是否属实
        if (!brand.getId().equals(order.getBrandId())){
            log.info("{发放交易余额}{当前订单不属于该店铺:" + order.getOrderSn() +"}");
            logService.logOrderFail("发放交易余额","当前订单不属于该店铺:"+order.getOrderSn());
            throw new RuntimeException("当前订单不属于该店铺");
        }

        //获取店铺用户
        LitemallUser user = userService.findById(brand.getUserId());
        if (!ObjectUtils.allNotNull(user , user.getTrueName() , user.getOpenid())) {
            log.info("{发放交易余额}{店家信息不正确:" + brand.getId() +"}");
            logService.logOrderFail("发放交易余额","店家信息不正确:"+brand.getId());
            throw new RuntimeException("店家信息不正确");
        }

        return user;
    }

}
